﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;


using ecdl.demo.model.expression;

using DocumentFormat.OpenXml;
using DocumentFormat.OpenXml.Wordprocessing;
using DocumentFormat.OpenXml.Packaging;

using System.Xml.Serialization;
using System.Xml;
using System.Text.RegularExpressions;
using ecdl.demo.persistence;

namespace ecdl.demo.model.expression {
    public class TextSelector : Selector {

        public TextSelector() {
            AddSelector(new TypedSelector<WordprocessingDocument, OpenXmlElement>(GetFromDocument));
            AddSelector(new TypedSelector<OpenXmlElement, OpenXmlElement>(GetFromElement));
        }

        public TextSelector(string regex, int regexGroup) : this(){
            this.RegEx = regex;
            this.RegexGroup = regexGroup;
        }

        public string RegEx { get; set; }

        public int  RegexGroup { get; set; }

        private IEnumerable<OpenXmlElement> GetFromDocument(WordprocessingDocument context) {
            return GetFromElement(context.MainDocumentPart.RootElement);
        }

        private IEnumerable<OpenXmlElement> GetFromElement(OpenXmlElement context) {
            return GetMatchingRuns(context.Descendants<Run>());
        }

        private string FullTextOf(Paragraph p) {
            StringBuilder buffer = new StringBuilder();
            foreach (var textElement in p.Descendants<Text>()) {
                buffer.Append(textElement.InnerText);
            }
            return buffer.ToString();
        }

        private IEnumerable<Run> GetMatchingRuns(IEnumerable<Run> runs) {
            var sequence = RunSequence.Create(runs);

            Match match = Regex.Match(sequence.Text, RegEx);
            if (match.Success) {
                Group group = match.Groups[RegexGroup];
                return sequence.GetRunsBetween(group.Index, group.Length);
            }
            return Enumerable.Empty<Run>();
        }

    }

    public class TextSelectorDTO : SingleExpressionDTO{
        public TextSelectorDTO() : base(typeof(TextSelector)){
        }

        [XmlAttribute("regex")]
        public string RegEx { get; set; }
        [XmlAttribute("group")]
        public int RegexGroup { get; set; }
    }

    public class RunSequence {
        private List<RunPosition> runs = new List<RunPosition>();

        public static RunSequence Create(IEnumerable<Run> runs) {
            RunSequence sequence = new RunSequence();
            foreach (var run in runs) {
                sequence.AddRun(run);
            }
            return sequence;
        }

        private int length = 0;
        private StringBuilder builder = new StringBuilder();
        private void AddRun(Run run) {
            string text = run.InnerText;
            builder.Append(text);
            runs.Add(new RunPosition(run, length));
            length += run.InnerText.Length;
        }

        public string Text {
            get {
                return builder.ToString();
            }
        }

        public IEnumerable<Run> GetRunsBetween(int startIndex, int length) {
            int endIndex = startIndex + length;
            IEnumerable<RunPosition> positions = runs.Where(run => !(run.StartIndex > endIndex || run.EndIndex < startIndex));   

            List<Run> affectedRuns = new List<Run>();
            foreach (var position in positions) {
                affectedRuns.Add(position.Run);
            }
            return affectedRuns;
        }

    }

    class RunPosition {
        public RunPosition(Run run, int startIndex) {
            this.Run = run;
            this.StartIndex = startIndex;
        }

        public Run Run { get; set; }

        public int StartIndex { get; set; }

        public int Length {
            get {
                return Run.InnerText.Length;
            }
        }
        public int EndIndex {
            get {
                return StartIndex + Length - 1;
            }
        }
    }
}
